| PIZZA | Current compiler version: 0.39d |
| A substantial companion to Java | |
| Changes from Pizza version 1.0 to 1.1 | |
|
Contents
Home Mirrors FAQ |
The Java 1.1 language standard is now fully supported, including support for inner classes and blank finals.
Cases in an algebraic data type are now represented by inner classes, contained within the algebraic class. Example:
class List<A> {
case Nil;
case Cons(A head, List<A> tail);
}
This algebraic class now produces classes List and List.Cons, whereas before it was List and Cons. This will break some old Pizza programs containing terms like:
new Cons(x, xs)
Cons cell;
The easiest way to make those programs work again is with an inner class import clause (see next item).
In Java 1.1, import clauses can refer to members of classes. For instance,
import List.*;
will import all classes contained in class List. In Pizza 1.1 this is generalized to also import all symbols defined by a case. That is:
import List.*;
will make available without qualification all of the following symbols:
More generally, importing an algebraic data type will make available all constructors of that type without qualification.
Pizza 1.1 supports deeply tail-recursive functions which do not overflow the stack. Since support for tail-recursion is implemented with closures and is therefore rather expensive, we use special syntax to force this optimization. The idiom
return goto f(<args>)
calls function f after releasing the caller's stack frame. If f's result type is void, one uses simply
goto f(<args>).
(The use of goto, which still is a reserved word in Java, was suggested to us by Guy Steele). Every function so called must be marked as a continuation. This is done by placing continue as a modifier in the function's declaration:
continue ResultType f (<params>)
In Pizza 1.1, continue is a new declaration modifier just like public or static.
Here's an example of a tail recursive function:
continue static int sum(int acc, List<int> xs) {
if (xs == Nil) return acc;
else return goto sum(acc + xs.head(), xs.tail());
}
This will run about 6-7 times slower than the "unoptimized" recursive function. On the other hand, the unoptimized function would overflow the stack for lists longer than 9000 elements while the tail-optimized function will work with lists of arbitrary length.
There are three rules governing the use of goto and continue in Pizza 1.1:
(1) every goto must be contained in a continuation.
(2) every goto must invoke a continuation.
(3) continuations are allowed to override normal methods but not vice versa.